package org.eclipseuseradmin.ui;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.eclipse.core.runtime.Platform;
import org.eclipse.ui.IEditorDescriptor;
import org.eclipse.ui.PlatformUI;
import org.eclipseuseradmin.internal.ui.UserAdminUiPlugin;
import org.eclipseuseradmin.internal.ui.editors.RoleElementInput;
import org.osgi.service.useradmin.Authorization;
import org.osgi.service.useradmin.Group;
import org.osgi.service.useradmin.Role;
import org.osgi.service.useradmin.User;
import org.osgi.service.useradmin.UserAdmin;

public abstract class BaseRoleElementAdapter implements IRoleElement {

	protected Role role;

	private String organizationUnitAttribute;

	private String[] acceptedChildren;

	public BaseRoleElementAdapter(Role role) {
		this.role = role;
	}

	public String getName() {
		return role.getName();
	}

	public String getOrganizationUnit() {
		return (String) role.getProperties()
				.get(getOrganizationUnitAttribute());
	}

	public void setOrganizationUnit(String organizationUnit) {

		role.getProperties().put(getOrganizationUnitAttribute(),
				organizationUnit);
	}

	public String getObjectClass() {
		return (String) role.getProperties().get("objectclass");
	}

	public void setObjectClass(String objectClass) {
		if (role.getProperties().get("objectclass") == null) {
			role.getProperties().put("objectclass", objectClass);
		}
	}

	public Role[] getChildren() {

		if (!(role instanceof Group)) {
			return new Role[0];
		}

		Group group = (Group) role;

		List<Role> children = new ArrayList<Role>();
		Role[] members = group.getMembers();
		if (members != null) {
			children.addAll(Arrays.asList(members));
		}
		members = group.getRequiredMembers();
		if (members != null) {
			children.addAll(Arrays.asList(members));
		}
		return children.toArray(new Role[children.size()]);
	}

	public Group[] getParents() {

		if (!(role instanceof User)) {
			return new Group[0];
		}

		User user = (User) role;

		UserAdmin userAdmin = getUserAdmin();
		Authorization authorization = userAdmin.getAuthorization(user);
		String[] impliedRoleNames = authorization.getRoles();
		List<Group> parents = new ArrayList<Group>();
		for (String impliedRoleName : impliedRoleNames) {

			Role impliedRole = userAdmin.getRole(impliedRoleName);
			if (impliedRole instanceof Group
					&& hasChild((Group) impliedRole, user)) {
				parents.add((Group) impliedRole);
			}
		}
		return parents.toArray(new Group[parents.size()]);
	}

	public boolean hasChildren() {

		if (!(role instanceof Group)) {
			return false;
		}

		Group group = (Group) role;

		return group.getMembers() != null || group.getRequiredMembers() != null;
	}

	public void addChild(Role child) {

		if (!(role instanceof Group)) {
			return;
		}

		Group group = (Group) role;

		group.addMember(child);
	}

	public void addParent(Group parent) {
	}

	public void removeChild(Role child) {

		if (!(role instanceof Group)) {
			return;
		}

		Group group = (Group) role;

		group.removeMember(child);
	}

	public void removeParent(Group parent) {
	}

	protected boolean hasChild(Group group, Role role) {

		Role[] members = group.getMembers();
		if (members != null) {
			for (Role member : members) {
				if (member.equals(role)) {
					return true;
				}
			}
		}
		members = group.getRequiredMembers();
		if (members != null) {
			for (Role member : members) {
				if (member.equals(role)) {
					return true;
				}
			}
		}
		return false;
	}

	public boolean acceptChild(Role child) {

		if (role.equals(child)) {
			return false;
		}

		String objectClass = (String) child.getProperties().get("objectclass");
		if (objectClass == null) {
			return false;
		}

		for (String acceptedObjectClass : getAcceptedChildren()) {

			if (acceptedObjectClass.equalsIgnoreCase(objectClass)) {
				return true;
			}
		}
		return false;
	}

	public String[] getAcceptedChildren() {

		if (acceptedChildren == null) {
			acceptedChildren = new String[0];
		}
		return acceptedChildren;
	}

	public void setAcceptedChildren(String[] acceptedChildren) {

		this.acceptedChildren = acceptedChildren;
	}

	public void delete() {

		getUserAdmin().removeRole(role.getName());
		role = null;
	}

	public String getOrganizationUnitAttribute() {

		if (organizationUnitAttribute == null) {
			organizationUnitAttribute = "ou";
		}
		return organizationUnitAttribute;
	}

	public void setOrganizationUnitAttribute(String organizationUnitAttribute) {
		this.organizationUnitAttribute = organizationUnitAttribute;
	}

	protected UserAdmin getUserAdmin() {

		return UserAdminUiPlugin.getUserAdmin();
	}

	public static IRoleElement adapt(Role role) {

		String objectClass = (String) role.getProperties().get("objectclass");
		String[] adapterTypes = Platform.getAdapterManager()
				.computeAdapterTypes(role.getClass());
		for (String adapterType : adapterTypes) {

			String simpleName = adapterType.substring(adapterType
					.lastIndexOf(".") + 1, adapterType.length());
			if (simpleName.equalsIgnoreCase(objectClass)
					|| simpleName.equalsIgnoreCase("I" + objectClass)) {
				return (IRoleElement) Platform.getAdapterManager().getAdapter(
						role, adapterType);
			}
		}
		return null;
	}

	public static IEditorDescriptor getDefaultEditor(IRoleElement roleElement) {

		Class[] classes = Platform.getAdapterManager().computeClassOrder(
				roleElement.getClass());
		for (Class clazz : classes) {
			IEditorDescriptor editorDescriptor = PlatformUI.getWorkbench()
					.getEditorRegistry().getDefaultEditor(clazz.getName());
			if (editorDescriptor != null) {
				return editorDescriptor;
			}
		}
		return null;
	}

	@Override
	public boolean equals(Object obj) {

		if (obj == this) {
			return true;
		}

		if (obj == null || obj.getClass() != this.getClass()) {
			return false;
		}

		return (role != null && role
				.equals(((BaseRoleElementAdapter) obj).role));
	}

}
